package vn.zalopay.benchmark.core.protobuf;

import org.apache.logging.log4j.util.Strings;

/** Represents a full grpc method, including package, service and method names. */
public class ProtoMethodName {
    // TODO(dino): Use autovalue for this class.
    private final String packageName;
    private final String serviceName;
    private final String methodName;

    /** Parses a string of the form"<package>.<service>/<method>". */
    public static ProtoMethodName parseFullGrpcMethodName(String fullMethodName) {
        // Ask grpc for the service name.
        String fullServiceName = io.grpc.MethodDescriptor.extractFullServiceName(fullMethodName);
        if (invalidMethodName(fullServiceName)) {
            throw new IllegalArgumentException(
                    "Could not extract full service from " + fullMethodName);
        }

        // Make sure there is a '/' and use the rest as the method name.
        int serviceLength = fullServiceName.length();
        if (serviceLength + 1 >= fullMethodName.length()
                || fullMethodName.charAt(serviceLength) != '/') {
            throw new IllegalArgumentException(
                    "Could not extract method name from " + fullMethodName);
        }
        String methodName = fullMethodName.substring(fullServiceName.length() + 1);

        // Extract the leading package from the service name.
        int index = fullServiceName.lastIndexOf('.');
        String packageName = index == -1 ? null : fullServiceName.substring(0, index);

        // Make sure the index is not at the end of the service name.
        if (index + 1 >= fullServiceName.length()) {
            throw new IllegalArgumentException("Could not extract service from " + fullServiceName);
        }
        String serviceName = fullServiceName.substring(index + 1);

        return new ProtoMethodName(packageName, serviceName, methodName);
    }

    private ProtoMethodName(String packageName, String serviceName, String methodName) {
        this.packageName = packageName;
        this.serviceName = serviceName;
        this.methodName = methodName;
    }

    /** Returns the full package name of the method. */
    public String getPackageName() {
        return packageName;
    }

    /** Returns the (unqualified) service name of the method. */
    public String getServiceName() {
        return serviceName;
    }

    /** Returns the (unqualified) method name of the method. */
    public String getMethodName() {
        return methodName;
    }

    public static boolean invalidMethodName(String fullServiceName) {
        return Strings.isBlank(fullServiceName);
    }
}
